package com.cwx.mychat.openai.service;

import com.cwx.mychat.entity.constant.CodeConstant;
import com.cwx.mychat.entity.dto.ModelConfigDto;
import com.cwx.mychat.entity.dto.TokenUserInfoDto;
import com.cwx.mychat.openai.config.BookingToolsConfig;
import com.cwx.mychat.openai.factory.DeepSeekAIModelFactory;
import com.cwx.mychat.openai.factory.OpenAIModelFactory;
import com.cwx.mychat.utils.redis.RedisUtil;
import com.cwx.mychat.utils.stringUtils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 作者： cwx
 * 时间： 2024/12/31 17:01
 * 版本： 1.0
 * 注释：
 */
@Slf4j
@Configuration
public class AIChatAssistantService {


    private final ChatMemory chatMemory;

    //缓存chatClient
    private final Map<String, ChatClient> chatClientMap = new ConcurrentHashMap<>();

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private BookingToolsConfig bookingToolsConfig;

    AIChatAssistantService(){
        this.chatMemory = MessageWindowChatMemory.builder().build();
    }


    public Flux<String> assistant(String message, TokenUserInfoDto tokenUserInfoDto, String sessionId) {
        // 从 Redis 获取配置
        ModelConfigDto modelConfigDto = (ModelConfigDto) redisUtil.get(CodeConstant.REDIS_ROBOT_INFO);

        log.info("获取模型信息：{}", modelConfigDto);
        // 动态构建 ChatClient
        ChatClient chatClient = buildChatClient(modelConfigDto, tokenUserInfoDto);

        // 发起对话
        return chatClient.prompt()
                .user(message)
                .system(promptSystemSpec -> promptSystemSpec.params(new HashMap<>() {{
                    put("current_data", LocalDate.now().toString());
                    put("user_name", tokenUserInfoDto.getNickName());
                }}))
                .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION_ID, sessionId))
                .tools(bookingToolsConfig)
                .stream()
                .content()
                .concatWith(Flux.just(CodeConstant.STREAM_END));
    }

    private ChatClient buildChatClient(ModelConfigDto modelConfigDto, TokenUserInfoDto userInfo) {

        ChatClient.Builder builder = ChatClient.builder(new OpenAIModelFactory().create(modelConfigDto))
                .defaultSystem(getSystemPrompt(modelConfigDto, userInfo))
                .defaultAdvisors(
                        SimpleLoggerAdvisor.builder().build(),
                        PromptChatMemoryAdvisor.builder(chatMemory).build()
                );

        return builder.build();
    }

    private String getSystemPrompt(ModelConfigDto modelConfigDto, TokenUserInfoDto userInfo) {
        // 默认预设词
        String defaultPrompt = """
                你是一个AI助手，请根据用户的问题，以友好、乐于助人的方式来回复。
                跟你对话的人叫 {user_name}。
                在适当的位置中加入合适当前语境的表情包。
                你正在通过在线聊天系统进行互动。
                如果查询联系人需要提供联系人姓名。
                优先讲中文。
                如果有地址将地址在https的前面加上a标签。
                今天的日期是 {current_data}
                """;

        // 如果 Redis 中有自定义配置，则覆盖默认值
        if (modelConfigDto != null && !StringUtil.isEmpty(modelConfigDto.getSystemPrompt())) {
            return modelConfigDto.getSystemPrompt();
        }

        return defaultPrompt;
    }


}
